<?php
/**
 * 核心框架
 * @author sunhaoqiang(shqdev@163.com)
 * @time: 2019-08-25 16:38
*/
namespace script;

use script\RouteAnalysis;
use script\Route;
use script\Config;
use script\DecoratorBase;

class Frame
{
    public $config;
    public $route = [];
    public function __construct()
    {
        // 自动加载
        spl_autoload_register([$this,"autoloader"]);
        // 异常处理
        set_exception_handler([$this, 'exception']);
        // 错误处理
        set_error_handler([$this, 'error']);
        $this->loadConfig();
        $this->loadRoute();
        
        $this->init();
    }

    public function loadMiddleware($route)
    {
        $middleware = Config::get('Middleware');
        $global = $middleware['global'] ?? [];
        $decoratorBase = new DecoratorBase();
        foreach ($global as $value) {
            $decoratorBase->add((new $value));
        }

        $route = $middleware['route'][$route] ?? [];

        foreach ($route as $value) {
            $decoratorBase->add((new $value));
        }

        return $decoratorBase;
    }

    /**
     * 加载配置
     *
     * @return void
     * @author sunhaoqiang(shqdev@163.com)
     * @time 2019-12-30 10:27
     */
    public function loadConfig()
    {
        $files = glob('./config/*');
        foreach ($files as $value) {
            preg_match('/\.\/(.*)\/(.*)\.php/', $value, $matches);
            [$file_name, $config, $cls] = $matches;
            $namespace = $config.'\\'.$cls;
            if (class_exists($namespace)) {
                Config::set($cls, (new $namespace));
            }
            
        }
    }

    /**
     * 加载路由
     *
     * @return void
     * @author sunhaoqiang(shqdev@163.com)
     * @time 2019-12-30 10:27
     */
    public function loadRoute()
    {
        $files = glob('./route/*');
        foreach ($files as $value) {
            preg_match('/\.\/(.*)\/(.*)\.php/', $value, $matches);
            [$file_name, $route, $cls] = $matches;
            $namespace = $route.'\\'.$cls;
            if (class_exists($namespace)) {
                foreach ((new $namespace) as $key => $value) {
                    Route::set($key, (new RouteAnalysis($key, $value)));
                }
            }
            
        }
    }

    public function autoloader($cls_name)
    {
        spl_autoload($cls_name);
    }

    public function exception($exception)
    {
        if (!$this->isCli()) {
            if (ENV) {
                if (!headers_sent()) {
                    header('Content-Type:application/json;charset=utf-8');
                }
                header("HTTP/1.1 500 Internal Server Error");
    
                $data = [
                    "code" => 500,
                    "msg" => $exception->getMessage(),
                    "data" => []
                ];
                exit(json_encode($data));
            }
            echo '<pre>';
        }
        echo $exception->getMessage()."\n\n";
        $trace = $exception->getTrace();
        foreach ($trace as $value) {
            if (isset($value['file']) && isset($value['line'])) {
                printf(" - 文件：%-80s\t    行号:%-4d 行 \n", $value['file'], $value['line']);
            }

        }
    }

    public function error($errno, $errstr, $errfile, $errline)
    {
        if (!(error_reporting() & $errno)) {
            // 此错误代码不包含在错误报告中，因此请将其删除到标准PHP错误处理程序
            return false;
        }
        
        $type = [
            E_ERROR => "运行时致命的错误。不能修复的错误。停止执行脚本",
            E_WARNING => "运行时非致命的错误。没有停止执行脚本",
            E_PARSE => "编译时的解析错误。解析错误应该只由解析器生成",
            E_NOTICE => "运行时的通知。脚本发现可能是一个错误，但也可能在正常运行脚本时发生",
            E_CORE_ERROR => "PHP 启动时的致命错误。这就如同 PHP 核心的 E_ERROR",
            E_CORE_WARNING => "PHP 启动时的非致命错误。这就如同 PHP 核心的 E_WARNING",
            E_COMPILE_ERROR => "编译时致命的错误。这就如同由 Zend 脚本引擎生成的 E_ERROR",
            E_COMPILE_WARNING => "编译时非致命的错误。这就如同由 Zend 脚本引擎生成的 E_WARNING",
            E_USER_ERROR => "用户生成的致命错误。这就如同由程序员使用 PHP 函数 trigger_error() 生成的 E_ERROR",
            E_USER_WARNING => "用户生成的非致命错误。这就如同由程序员使用 PHP 函数 trigger_error() 生成的 E_WARNING",
            E_USER_NOTICE => "用户生成的通知。这就如同由程序员使用 PHP 函数 trigger_error() 生成的 E_NOTICE",
            E_STRICT => "运行时的通知。PHP 建议您改变代码，以提高代码的互用性和兼容性",
            E_RECOVERABLE_ERROR => "可捕获的致命错误。这就如同一个可以由用户定义的句柄捕获的 E_ERROR（见 set_error_handler()）",
            E_ALL => "所有的错误和警告的级别，除了 E_STRICT（自 PHP 6.0 起，E_STRICT 将作为 E_ALL的一部分）"
        ];

        if (key_exists($errno, $type)) {
            $msg = "[错误类型]：".$type[$errno]."\n";
            $msg .= "[错误说明]：".$errstr."";
        }else {
            $msg = "[错误类型]：未知\n";
            $msg .= "[错误说明]：未知错误";
        }
        
        throw new \Exception($msg);
    }

    public function isCli()
    {
        return PHP_SAPI === 'cli';
    }

    public function isWinnt()
    {
        return PHP_OS === 'WINNT';
    }

    public function init()
    {
        if ($this->isCli()) {
            $this->initCli();
        } else {
            // URI 访问
            
            if (isset($_SERVER['REQUEST_URI'])) {
                // $route = substr($_SERVER['REQUEST_URI'], strlen('/'));
                [$route, $query] = explode('?' ,$_SERVER['REQUEST_URI']);
                if(Route::exists($route)){
                    $middleware = $this->loadMiddleware($route);
                    Route::get($route)->add($middleware)->run();
                }
            }

        }
          
    }

    public function initCli()
    {
        if (!$this->isCli()) {
            echo "您运行php文件不是命令行脚本！！！\n";
            exit;
        }

        global $argc,$argv;
        if ($argc < 2) {            
            // 不传参时的脚本执行，意为默认脚本
            echo '默认脚本';
            exit;
        }

        // 传参时指定脚本
        if(isset($argv[1]) && Route::exists($argv[1])){
            printf("------------------------\t %s \t------------------------\n\n", date('Y-m-d H:i:s'));
            Route::get($argv[1])->run();
            printf("------------------------\t %s \t------------------------\n", date('Y-m-d H:i:s'));
            exit;
        }

    }
}
